package repository

import (
	"sen-golang-study/go_game_study/hero_story_go_server/game_server/internal/domain/session/entity"
	"sen-golang-study/go_game_study/hero_story_go_server/game_server/internal/domain/session/valueobject"
	"sync"
)

// SessionRepositoryImpl 会话仓储内存实现
type SessionRepositoryImpl struct {
	sessions  *sync.Map // sessionID -> *entity.Session
	userIndex *sync.Map // userID -> sessionID
	mutex     sync.RWMutex
}

// NewSessionRepository 创建会话仓储实现
func NewSessionRepository() SessionRepository {
	return &SessionRepositoryImpl{
		sessions:  &sync.Map{},
		userIndex: &sync.Map{},
	}
}

// Save 保存会话
func (r *SessionRepositoryImpl) Save(session *entity.Session) error {
	if session == nil {
		return nil
	}

	r.sessions.Store(session.GetSessionID(), session)

	// 如果会话已绑定用户，更新用户索引
	if session.IsUserBound() {
		r.userIndex.Store(session.GetUserID(), session.GetSessionID())
	}

	return nil
}

// GetBySessionID 根据会话ID获取会话
func (r *SessionRepositoryImpl) GetBySessionID(sessionID string) (*entity.Session, error) {
	if len(sessionID) == 0 {
		return nil, nil
	}

	value, exists := r.sessions.Load(sessionID)
	if !exists {
		return nil, nil
	}

	return value.(*entity.Session), nil
}

// GetByUserID 根据用户ID获取会话
func (r *SessionRepositoryImpl) GetByUserID(userID uint32) (*entity.Session, error) {
	if userID == 0 {
		return nil, nil
	}

	value, exists := r.userIndex.Load(userID)
	if !exists {
		return nil, nil
	}

	sessionID := value.(string)
	return r.GetBySessionID(sessionID)
}

// Update 更新会话
func (r *SessionRepositoryImpl) Update(session *entity.Session) error {
	if session == nil {
		return nil
	}

	// 检查会话是否存在
	_, exists := r.sessions.Load(session.GetSessionID())
	if !exists {
		return nil
	}

	// 更新会话
	r.sessions.Store(session.GetSessionID(), session)

	// 更新用户索引
	if session.IsUserBound() {
		r.userIndex.Store(session.GetUserID(), session.GetSessionID())
	} else {
		// 如果用户已解绑，从用户索引中删除
		r.userIndex.Range(func(key, value interface{}) bool {
			if value.(string) == session.GetSessionID() {
				r.userIndex.Delete(key)
				return false
			}
			return true
		})
	}

	return nil
}

// Delete 删除会话
func (r *SessionRepositoryImpl) Delete(sessionID string) error {
	if len(sessionID) == 0 {
		return nil
	}

	// 获取会话信息
	session, err := r.GetBySessionID(sessionID)
	if err != nil || session == nil {
		return err
	}

	// 从会话映射中删除
	r.sessions.Delete(sessionID)

	// 从用户索引中删除
	if session.IsUserBound() {
		r.userIndex.Delete(session.GetUserID())
	}

	return nil
}

// GetActiveSessions 获取所有活跃会话
func (r *SessionRepositoryImpl) GetActiveSessions() ([]*entity.Session, error) {
	var activeSessions []*entity.Session

	r.sessions.Range(func(key, value interface{}) bool {
		session := value.(*entity.Session)
		if session.IsActive() {
			activeSessions = append(activeSessions, session)
		}
		return true
	})

	return activeSessions, nil
}

// GetExpiredSessions 获取过期会话
func (r *SessionRepositoryImpl) GetExpiredSessions(timeoutMs int64) ([]*entity.Session, error) {
	var expiredSessions []*entity.Session

	r.sessions.Range(func(key, value interface{}) bool {
		session := value.(*entity.Session)
		if session.IsExpired(timeoutMs) {
			expiredSessions = append(expiredSessions, session)
		}
		return true
	})

	return expiredSessions, nil
}

// CleanExpiredSessions 清理过期会话
func (r *SessionRepositoryImpl) CleanExpiredSessions(timeoutMs int64) error {
	var expiredSessionIDs []string

	r.sessions.Range(func(key, value interface{}) bool {
		session := value.(*entity.Session)
		if session.IsExpired(timeoutMs) {
			expiredSessionIDs = append(expiredSessionIDs, session.GetSessionID())
			// 标记为过期
			session.SetStatus(valueobject.SessionStatusExpired)
		}
		return true
	})

	// 删除过期会话
	for _, sessionID := range expiredSessionIDs {
		if err := r.Delete(sessionID); err != nil {
			// 记录删除失败的错误，但继续处理其他会话
			continue
		}
	}

	return nil
}

// GetSessionCount 获取会话总数
func (r *SessionRepositoryImpl) GetSessionCount() (int, error) {
	count := 0
	r.sessions.Range(func(key, value interface{}) bool {
		count++
		return true
	})
	return count, nil
}

// GetActiveSessionCount 获取活跃会话数
func (r *SessionRepositoryImpl) GetActiveSessionCount() (int, error) {
	count := 0
	r.sessions.Range(func(key, value interface{}) bool {
		session := value.(*entity.Session)
		if session.IsActive() {
			count++
		}
		return true
	})
	return count, nil
}
